package com.groupbuying.redpacket.service.impl;

import com.alibaba.fastjson.JSON;
import com.groupbuying.redpacket.bo.RedPacketLimitBO;
import com.groupbuying.redpacket.bo.RedPacketListBO;
import com.groupbuying.redpacket.constants.LargeScreenConstants;
import com.groupbuying.redpacket.constants.RedPacketTaskEnumConstants;
import com.groupbuying.redpacket.constants.RedisConstans;
import com.groupbuying.redpacket.dao.RedPacketLimitInfoDao;
import com.groupbuying.redpacket.dao.RedPacketListDao;
import com.groupbuying.redpacket.dao.RedPacketTaskDao;
import com.groupbuying.redpacket.domain.RedPacketTaskDO;
import com.groupbuying.redpacket.service.HandleRedPacketTaskService;
import com.groupbuying.redpacket.utils.RedisUtils;
import com.groupbuying.redpacket.utils.apiresult.ApiResult;
import com.groupbuying.redpacket.utils.apiresult.ApiResultCode;
import com.groupbuying.redpacket.websocket.LargeScreenWebSocketServer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName HandleRedPackageTaskServiceImpl
 * @Description: TODO   执行红包任务服务实现
 * @Author srlg3
 * @Date 2019/11/15
 * @Version V1.0
 **/
@Service
public class HandleRedPacketTaskServiceImpl implements HandleRedPacketTaskService {
    Logger logger = LoggerFactory.getLogger(HandleRedPacketTaskServiceImpl.class);

    @Autowired
    private RedPacketTaskDao redPacketTaskDao;

    @Autowired
    private RedPacketListDao redPacketListDao;

    @Autowired
    private RedPacketLimitInfoDao redPacketLimitInfoDao;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean taskStart(String taskId) {

        //log
        StringBuilder build = new StringBuilder();
        build.append("任务关闭,任务id：").append(taskId);

        if (StringUtils.isEmpty(taskId)) {
            logger.error("{},错误提示：任务id不能为空",build);
            return false;
        }

        //1. 查询当前任务信息
        RedPacketTaskDO taskDO = redPacketTaskDao.get(Long.parseLong(taskId));

        if (taskDO == null) {
            logger.error("{},错误提示：查询任务信息为空",build);
            return false;
        }

        int keepTime = taskDO.getKeepTime();
        //如果当前数据不是待执行状态直接退出
        if (!RedPacketTaskEnumConstants.ENUM_EXECUTESTATE_WAIT_FOR_EXEC.equals(taskDO.getExecuteState())) {
            logger.error("{},错误提示:当前状态不是待执行状态",build);
            return false;
        }

        Date date = taskDO.getStartTime();
        Integer startType = taskDO.getStartType();

        //如果是定时启动方式
        if (RedPacketTaskEnumConstants.ENUM_STARTTYPE_AUTO.equals(startType)) {

            //计算差值
            long subSec = Math.abs(date.getTime() - System.currentTimeMillis())/1000/60 ;
            logger.info("{},当前误差秒数为：{}秒",build,subSec);

            //是否在误差范围
            if (subSec > RedPacketTaskEnumConstants.ENUM_AUTO_START_ERORR){
                logger.info("{},定时任务启动时间还未到,无法开始,超出{}秒误差时间",build,RedPacketTaskEnumConstants.ENUM_AUTO_START_ERORR);
                return false;
            }
        }

        //2. 放入redis当中
        //redis key
        //启动任务控制的key
        String redisKey = RedisConstans.RED_PACKAGE_CONTROL;
        //启动任务对应的红包容器key
        String redisRedPackageKey = redisKey + taskId ;

        //判断是否有
        if (redisUtils.isHasKey(redisKey)) {
            logger.error("{},错误提示：redis 重复开启任务启动",build);
            return false;
        }
        //TODO 获取限制数
        RedPacketLimitBO redPacketLimitBO = redPacketLimitInfoDao.redPacketLimitInfoByTaskId(taskId);

        if (redPacketLimitBO == null) {
            logger.error("{},错误提示：查询限制信息为空",build);
            return false;
        }

        //保存限制信息到redis
        boolean ret = redisUtils.setIfAbsent(redisKey, redPacketLimitBO, keepTime);
        if (!ret) {
            logger.error("{},错误提示：redis 保存限制数据有误",build);
            return false;
        }

        //保存限制信息到redis 用于结算页面  (过期时间=活动时间+大屏结算页面时间)
        ret = redisUtils.setIfAbsent(RedisConstans.RED_PACKAGE_CONTROL_SETTLE, redPacketLimitBO, keepTime + LargeScreenConstants.LARGE_SCREEN_SETTLE_PAGE_TIME);
        if (!ret) {
            logger.error("{},错误提示：redis 保存限制数据有误,当前是结算状态不能开始任务",build);
            redisUtils.delKey(redisKey);
            return false;
        }

        //保存红包信息到redis当中
        List<RedPacketListBO> listBOs = redPacketListDao.getRedPacketBOByTaskId(taskId);

        if (listBOs == null) {
            logger.error("{},错误提示：没有查询到红包BO",build);
            redisUtils.delKey(redisKey);
            return false;
        }

        redisUtils.delKey(redisRedPackageKey);
        long lRet = redisUtils.sSet(redisRedPackageKey,listBOs.toArray());
        if (lRet == 0L || lRet < listBOs.size()) {
            redisUtils.delKey(redisKey);
            logger.error("{},错误提示：redis 保存红包数有误",build);
            return false;
        }

        //4. 修改任务状态为开始状态
        Date nowTime = new Date();
        RedPacketTaskDO redPacketTaskDO = new RedPacketTaskDO();
        redPacketTaskDO.setId(Long.parseLong(taskId));
        redPacketTaskDO.setUpdateTime(nowTime);
        redPacketTaskDO.setExecuteState(RedPacketTaskEnumConstants.ENUM_EXECUTESTATE_GOING);
        //手动开启任务更新开始时间
        if (RedPacketTaskEnumConstants.ENUM_STARTTYPE_HAND.equals(startType)) {
            redPacketTaskDO.setStartTime(nowTime);
        }

        //5. 更新状态
        try {
            redPacketTaskDao.update(redPacketTaskDO);

            //发送websocket通知任务开始
            Map<String,Object> retMap = new HashMap<>();
            //红包限制信息
            retMap.put(LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_FIELD_LIMIT,redPacketLimitBO);
            //任务开始状态
            retMap.put(LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_FIELD_STATE,LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_STATE_RUNNING_START);

            LargeScreenWebSocketServer.sendInfo(JSON.toJSONString(ApiResult.success(ApiResultCode.SUCCESS,retMap)));
        } catch (Exception e){
            logger.error("{},错误提示：更新状态失败或者socket发送失败",build);
            redisUtils.delKey(redisKey);
            redisUtils.delKey(redisRedPackageKey);
            return false;
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean taskFinish(String taskId) {

        //log
        StringBuilder build = new StringBuilder();
        build.append("任务关闭,任务id：").append(taskId);

        if (StringUtils.isEmpty(taskId)) {
            logger.error("{},错误提示：任务id不能为空",build);
            return false;
        }

        //1. 查询当前任务信息
        RedPacketTaskDO taskDO = redPacketTaskDao.get(Long.parseLong(taskId));

        if (taskDO == null) {
            logger.error("{},错误提示：查询任务信息为空",build);
            return false;
        }

        //启动任务方式
        Integer startType = taskDO.getStartType();

        //如果状态是执行结束状态直接退出
        if (RedPacketTaskEnumConstants.ENUM_EXECUTESTATE_FINISHED.equals(taskDO.getExecuteState())) {
            logger.info("{},提示:当前已是关闭状态",build);
            return true;
        }

        //如果状态不是执行状态，就不能操作
        if (!RedPacketTaskEnumConstants.ENUM_EXECUTESTATE_GOING.equals(taskDO.getExecuteState())) {
            logger.error("{},错误提示：任务当前状态有误",build);
            return false;
        }

        //3. 修改任务状态为关闭状态
        Date nowTime = new Date();
        RedPacketTaskDO redPacketTaskDO = new RedPacketTaskDO();
        redPacketTaskDO.setId(Long.parseLong(taskId));
        redPacketTaskDO.setUpdateTime(nowTime);
        redPacketTaskDO.setExecuteState(RedPacketTaskEnumConstants.ENUM_EXECUTESTATE_FINISHED);
        //手动结束任务更新结束时间
        if (RedPacketTaskEnumConstants.ENUM_STARTTYPE_HAND.equals(startType)) {
            redPacketTaskDO.setEndTime(nowTime);
        }

        //查询任务限制状态用于结算页面
        RedPacketLimitBO redPacketLimitBO = (RedPacketLimitBO) redisUtils.getValue(RedisConstans.RED_PACKAGE_CONTROL_SETTLE);

        if (redPacketLimitBO == null) {
            logger.error("{},错误提示:redis查询限制条件失败",build);
        }

        //4. 更新状态
        try {
            redPacketTaskDao.update(redPacketTaskDO);

            //发送websocket通知任务结束
            Map<String,Object> retMap = new HashMap<>();
            //红包限制信息
            retMap.put(LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_FIELD_LIMIT,"");
            //任务结束状态
            retMap.put(LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_FIELD_STATE,LargeScreenConstants.LARGE_SCREEN_PUSH_SOCKET_STATE_RUNNING_END);

            LargeScreenWebSocketServer.sendInfo(JSON.toJSONString(ApiResult.success(ApiResultCode.SUCCESS,retMap)));
        } catch (Exception e){
            logger.error("{},错误提示：更新状态失败或者socket发送失败",build);
            return false;
        }

        //redis key
        String redisKey = RedisConstans.RED_PACKAGE_CONTROL;

        redisUtils.delKey(redisKey);
//        redisUtils.delKey(redisKey+taskId);

        return true;
    }
}
